home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / src / sprited / fs / fsNameOps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-02  |  24.5 KB  |  833 lines

  1. /* 
  2.  * fsNameOps.c --
  3.  *
  4.  *    This has procedures for the operations done on file names
  5.  *    like open and remove.  The name lookups are done via
  6.  *    Fsprefix_LookupOperation which uses the prefix table to choose the server.
  7.  *
  8.  * Copyright (C) 1987 Regents of the University of California
  9.  * All rights reserved.
  10.  * Permission to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose and without
  12.  * fee is hereby granted, provided that the above copyright
  13.  * notice appear in all copies.  The University of California
  14.  * makes no representations about the suitability of this
  15.  * software for any purpose.  It is provided "as is" without
  16.  * express or implied warranty.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /user5/kupfer/spriteserver/src/sprited/fs/RCS/fsNameOps.c,v 1.2 91/12/01 21:58:16 kupfer Exp $ SPRITE (Berkeley)";
  21. #endif not lint
  22.  
  23.  
  24. #include <sprite.h>
  25. #include <string.h>
  26.  
  27. #include <dbg.h>
  28. #include <fs.h>
  29. #include <fsMach.h>
  30. #include <fsio.h>
  31. #include <fsutil.h>
  32. #include <fsNameOps.h>
  33. #include <fsutilTrace.h>
  34. #include <fsStat.h>
  35. #include <fsprefix.h>
  36. #include <proc.h>
  37. #include <rpc.h>
  38. #include <utilsMach.h>
  39.  
  40.  
  41. /*
  42.  *----------------------------------------------------------------------
  43.  *
  44.  * Fs_Open --
  45.  *
  46.  *      This routine sets up a Fs_Stream object for the named file.  The
  47.  *      parameters specify the manner in which the stream will be used and
  48.  *      a set of permission bits in case a file needs to be created for
  49.  *      the stream.
  50.  *
  51.  * Results:
  52.  *      An error code, and a pointer to a Fs_Stream object for the file.
  53.  *      This is used in further operations on the file and is released
  54.  *      with Fs_Close
  55.  *
  56.  * Side effects:
  57.  *    The stream is opened.
  58.  *
  59.  *----------------------------------------------------------------------
  60.  */
  61. ReturnStatus
  62. Fs_Open(name, useFlags, type, permissions, streamPtrPtr)
  63.     char     *name;        /* The name of the file to open */
  64.     register int useFlags;    /* Indicates read/write etc. the valid bits 
  65.                  * to include are defined in fs.h */
  66.     int     type;        /* If FS_FILE then any type of file can be 
  67.                  * opened, except if useFlags includes 
  68.                  * FS_CREATE then a regular file will be 
  69.                  * created.  Otherwise only the specified 
  70.                  * type can be opened (or created). */
  71.     int     permissions;    /* A mask indicating the permission bits to 
  72.                  * turn on if the file gets created */
  73.     Fs_Stream     **streamPtrPtr;    /* Contents set to point to a valid stream
  74.                   * or NIL if there was an error. */
  75. {
  76.     register Fs_Stream     *streamPtr;    /* Local copy of stream pointer */
  77.     ReturnStatus     status;        /* Return error code from RPC */
  78. #ifdef SOSP91
  79.     Fs_OpenArgsSOSP         openArgs;    /* Packaged up parameters */
  80. #else
  81.     Fs_OpenArgs         openArgs;    /* Packaged up parameters */
  82. #endif
  83.     Fs_OpenResults     openResults;    /* Packaged up results */
  84.     Proc_ControlBlock    *procPtr;    /* Used to get process IDs */
  85.     Fs_NameInfo        *nameInfoPtr;    /* Used to track name and prefix */
  86.  
  87.     *streamPtrPtr = (Fs_Stream *)NIL;
  88.  
  89.     if ((useFlags & FS_EXECUTE) && (useFlags & (FS_WRITE | FS_CREATE))) {
  90.     return(FS_INVALID_ARG);
  91.     }
  92.     
  93.     /*
  94.      * Override the type if user flags indicate special files.
  95.      */
  96.     if (useFlags & FS_NAMED_PIPE_OPEN) {
  97.     printf( "Named pipes (%s) not implemented\n", name);
  98.     return(FS_INVALID_ARG);
  99.     } else if (useFlags & FS_PDEV_MASTER) {
  100.     type = FS_PSEUDO_DEV;
  101.     } else if (useFlags & FS_PFS_MASTER) {
  102.     type = FS_REMOTE_LINK;
  103.     useFlags &= ~FS_FOLLOW;
  104.     }
  105.     /*
  106.      * Make sure we check for write permission before truncating.
  107.      */
  108.     if (useFlags & FS_TRUNC) {
  109.     useFlags |= FS_WRITE;
  110.     }
  111.  
  112.     /*
  113.      * Set up arguments to the Domain specific open routine.  The domain
  114.      * open routine returns streamData used to set up the I/O handle
  115.      * by the client open routine called below.  The stream's nameInfo is
  116.      * set up as a side effect of going through Fsprefix_LookupOperation.
  117.      */
  118.     procPtr = Proc_GetEffectiveProc();
  119.     if (type != FS_SYMBOLIC_LINK && type != FS_REMOTE_LINK) {
  120.     openArgs.permissions    = permissions & procPtr->fsPtr->filePermissions;
  121.     } else {
  122.     openArgs.permissions    = permissions;
  123.     }
  124.     openArgs.useFlags        = useFlags;
  125.     openArgs.type        = type;
  126.     openArgs.clientID        = rpc_SpriteID;
  127.     if (procPtr->genFlags & PROC_FOREIGN) {
  128.     openArgs.migClientID    = procPtr->peerHostID;
  129.     } else {
  130.     openArgs.migClientID    = rpc_SpriteID;
  131.     }
  132.     openResults.streamData    = (ClientData) NIL;
  133.     Fs_SetIDs(procPtr, &openArgs.id);
  134. #ifdef SOSP91
  135.     openArgs.realID = procPtr->userID;
  136.     openResults.dataSize = sizeof(Fs_OpenArgsSOSP);
  137. #endif
  138.     nameInfoPtr = mnew(Fs_NameInfo);
  139.  
  140.     FSUTIL_TRACE_NAME(FSUTIL_TRACE_OPEN_START, name);
  141.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_OPEN, useFlags & FS_FOLLOW,
  142.             (Address)&openArgs, (Address)&openResults, nameInfoPtr);
  143.     FSUTIL_TRACE_NAME(FSUTIL_TRACE_OPEN_DONE, name);
  144.     if (status == SUCCESS) {
  145.     /*
  146.      * Install the stream and then call the client open procedure
  147.      * to complete the setup of the stream's I/O handle
  148.      */
  149.     streamPtr = Fsio_StreamAddClient(&openResults.streamID, rpc_SpriteID,
  150.                  (Fs_HandleHeader *)NIL,
  151.                  useFlags, name, (Boolean *)NIL, (Boolean *)NIL);
  152.     streamPtr->nameInfoPtr = nameInfoPtr;
  153.     Fsutil_HandleUnlock(streamPtr);
  154.     status = (*fsio_StreamOpTable[openResults.ioFileID.type].ioOpen)
  155.             (&openResults.ioFileID, &streamPtr->flags, rpc_SpriteID,
  156.              openResults.streamData, name, &streamPtr->ioHandlePtr);
  157.     if (status == SUCCESS) {
  158.         if (streamPtr->flags & FS_TRUNC) {
  159.         (void)Fs_TruncStream(streamPtr, 0);
  160.         }
  161. #ifdef SOSP91
  162.         streamPtr->hdr.flags &= ~FSUTIL_RW_FLAGS;
  163. #endif
  164.         *streamPtrPtr = streamPtr;
  165.         switch (useFlags & (FS_READ | FS_WRITE)) {
  166.         case FS_READ:
  167.             fs_Stats.cltName.numReadOpens ++;
  168.             break;
  169.         case FS_WRITE:
  170.             fs_Stats.cltName.numWriteOpens ++;
  171.             break;
  172.         case (FS_READ | FS_WRITE):
  173.             fs_Stats.cltName.numReadWriteOpens ++;
  174.             break;
  175.         default:
  176.             break;
  177.         }
  178.     } else {
  179.         /*
  180.          * Client open procedure failed.  Clean up the stream.
  181.          */
  182.         Fsutil_HandleLock(streamPtr);
  183.         (void)Fsio_StreamClientClose(&streamPtr->clientList, rpc_SpriteID);
  184.         Fsio_StreamDestroy(streamPtr);
  185.     }
  186.     } else {
  187.     ckfree((Address)nameInfoPtr);
  188.     }
  189.     return(status);
  190. }
  191.  
  192. /*
  193.  *----------------------------------------------------------------------
  194.  *
  195.  * Fs_SetIDs --
  196.  *
  197.  *    Get user ID and group IDs from the proc table.  The FsUserID
  198.  *    struct includes storage for the list of groups.  Alternatively,
  199.  *    it could contain a pointer to the groups in the proc table.
  200.  *
  201.  *    TODO: Byte the bullet and figure out a nice way to pass a
  202.  *    variable length list of groups around.  Then this procedure
  203.  *    would not be needed, and the Fs_ProcessState could be
  204.  *    referenced directly.  The ugliest place to do all this is
  205.  *    in the RPC stubs.
  206.  *
  207.  * Results:
  208.  *    None.
  209.  *
  210.  * Side effects:
  211.  *    Instantiate *idPtr to hold the user and group IDs of the current proc.
  212.  *
  213.  *----------------------------------------------------------------------
  214.  */
  215. void
  216. Fs_SetIDs(procPtr, idPtr)
  217.     Proc_ControlBlock         *procPtr;
  218.     Fs_UserIDs            *idPtr;
  219. {
  220.     register    Fs_ProcessState *fsPtr;
  221.     register    int    *procGroupIDs;
  222.     register    int    *groupPtr;
  223.     register     int     i;
  224.  
  225.     if (procPtr == (Proc_ControlBlock *)NIL) {
  226.     procPtr = Proc_GetEffectiveProc();
  227.     }
  228.     idPtr->user = procPtr->effectiveUserID;
  229.  
  230.     fsPtr = procPtr->fsPtr;
  231.     if (fsPtr == (Fs_ProcessState *)NIL) {
  232.     /*
  233.      * Exiting processes remove swap files after clearing fs state.
  234.      */
  235.     idPtr->numGroupIDs = 0;
  236.     procGroupIDs = (int *)NIL;
  237.     } else {
  238.     idPtr->numGroupIDs = fsPtr->numGroupIDs;
  239.     procGroupIDs = fsPtr->groupIDs;
  240.     }
  241.     for (i = 0, groupPtr = idPtr->group; i < FS_NUM_GROUPS;  i++, groupPtr++) {
  242.     /*
  243.      * The file system state record supports a variable length array of
  244.      * group IDs but here we truncate it...
  245.      */
  246.     if (i < idPtr->numGroupIDs) {
  247.         *groupPtr = *procGroupIDs;
  248.         procGroupIDs++;
  249.     } else {
  250.         *groupPtr = -1;
  251.     }
  252.     }
  253. }
  254.  
  255. /*
  256.  *----------------------------------------------------------------------
  257.  *
  258.  * Fs_Remove --
  259.  *
  260.  *    Remove the named file.  Because each entry in a directory is only
  261.  *    one of many posible references, the disk space for the file may or
  262.  *    may not be freed after this call.   Only when the last link to
  263.  *    the file is removed is the disk space freed up.  This does not
  264.  *    follow links so that links are removed instead of the file
  265.  *    they reference.
  266.  *
  267.  * Results:
  268.  *    An error code.
  269.  *
  270.  * Side effects:
  271.  *    The file is removed
  272.  *
  273.  *----------------------------------------------------------------------
  274.  */
  275. ReturnStatus
  276. Fs_Remove(name)
  277.     char *name;        /* The name of the file to remove */
  278. {
  279.     ReturnStatus status;
  280.     Fs_LookupArgs lookupArgs;
  281.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  282.  
  283.     lookupArgs.useFlags = FS_DELETE;
  284.     Fs_SetIDs(procPtr, &lookupArgs.id);
  285.     lookupArgs.clientID = rpc_SpriteID;
  286.     if (procPtr->genFlags & PROC_FOREIGN) {
  287.     lookupArgs.migClientID    = procPtr->peerHostID;
  288.     } else {
  289.     lookupArgs.migClientID    = rpc_SpriteID;
  290.     }
  291.     fs_Stats.cltName.removes++;
  292.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_REMOVE, 0,
  293.              (Address)&lookupArgs, (Address)NIL, (Fs_NameInfo *)NIL);
  294.     return(status);
  295. }
  296.  
  297. /*
  298.  *----------------------------------------------------------------------
  299.  *
  300.  * Fs_RemoveDir --
  301.  *
  302.  *    Remove the named directory.  It must be empty, that is it should
  303.  *    only contain entries for itself (.) and its parent (..).
  304.  *
  305.  * Results:
  306.  *    An error code.
  307.  *
  308.  * Side effects:
  309.  *    The directory is removed if possible
  310.  *
  311.  *----------------------------------------------------------------------
  312.  */
  313. ReturnStatus
  314. Fs_RemoveDir(name)
  315.     char *name;        /* The name of the directory to remove */
  316. {
  317.     ReturnStatus status;
  318.     Fs_LookupArgs lookupArgs;
  319.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  320.  
  321.     lookupArgs.useFlags = FS_DELETE;
  322.     Fs_SetIDs(procPtr, &lookupArgs.id);
  323.     lookupArgs.clientID = rpc_SpriteID;
  324.     if (procPtr->genFlags & PROC_FOREIGN) {
  325.     lookupArgs.migClientID    = procPtr->peerHostID;
  326.     } else {
  327.     lookupArgs.migClientID    = rpc_SpriteID;
  328.     }
  329.     fs_Stats.cltName.removeDirs++;
  330.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_REMOVE_DIR, 0,
  331.              (Address)&lookupArgs, (Address)NIL, (Fs_NameInfo *)NIL);
  332.     return(status);
  333. }
  334.  
  335. /*
  336.  *----------------------------------------------------------------------
  337.  *
  338.  * Fs_MakeDevice --
  339.  *
  340.  *    Make the named device file.  This is the procedure which
  341.  *    does the actual work for the Fs_MakeDevice system call.
  342.  *
  343.  * Results:
  344.  *    An error code.
  345.  *
  346.  * Side effects:
  347.  *    The device file is made
  348.  *
  349.  *----------------------------------------------------------------------
  350.  */
  351. ReturnStatus
  352. Fs_MakeDevice(name, devicePtr, permissions)
  353.     char *name;            /* The name of the directory to make */
  354.     Fs_Device *devicePtr;    /* Specifies device info */
  355.     int permissions;        /* The permissions for the new directory */
  356. {
  357.     ReturnStatus status;    /* Return error code */
  358.     Fs_MakeDeviceArgs makeDevArgs;/* Packaged up parameters */
  359.     Proc_ControlBlock *procPtr;    /* Used to get process IDs */
  360.  
  361.     if (((devicePtr->serverID != FS_LOCALHOST_ID) &&
  362.     (devicePtr->serverID <= 0)) ||
  363.     (devicePtr->type < 0) ||
  364.     (devicePtr->unit < 0)) {
  365.     return(FS_INVALID_ARG);
  366.     }
  367.     procPtr = Proc_GetEffectiveProc();
  368.     makeDevArgs.device         = *devicePtr;
  369.     makeDevArgs.open.permissions= permissions & procPtr->fsPtr->filePermissions;
  370.     Fs_SetIDs(procPtr, &makeDevArgs.open.id);
  371.     makeDevArgs.open.clientID    = rpc_SpriteID;
  372.     if (procPtr->genFlags & PROC_FOREIGN) {
  373.     makeDevArgs.open.migClientID    = procPtr->peerHostID;
  374.     } else {
  375.     makeDevArgs.open.migClientID    = rpc_SpriteID;
  376.     }
  377.  
  378.     fs_Stats.cltName.makeDevices++;
  379.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_MAKE_DEVICE, 0,
  380.              (Address)&makeDevArgs, (Address)NIL, (Fs_NameInfo *)NIL);
  381.     return(status);
  382. }
  383.  
  384. /*
  385.  *----------------------------------------------------------------------
  386.  *
  387.  * Fs_MakeDir --
  388.  *
  389.  *    Make the named directory.  This is the procedure which
  390.  *    does the actual work for the Fs_MakeDir system call.
  391.  *
  392.  * Results:
  393.  *    An error code.
  394.  *
  395.  * Side effects:
  396.  *    The directory is made
  397.  *
  398.  *----------------------------------------------------------------------
  399.  */
  400. ReturnStatus
  401. Fs_MakeDir(name, permissions)
  402.     char *name;        /* The name of the directory to make */
  403.     int permissions;    /* The permissions for the new directory */
  404. {
  405.     ReturnStatus status;    /* Return error code from RPC */
  406.     Fs_OpenArgs openArgs;    /* Packaged up parameters */
  407.     Proc_ControlBlock *procPtr;    /* Used to get process IDs */
  408.  
  409.     procPtr = Proc_GetEffectiveProc();
  410.     openArgs.useFlags = FS_CREATE | FS_EXCLUSIVE | FS_FOLLOW ;
  411.     openArgs.permissions = permissions & procPtr->fsPtr->filePermissions;
  412.     openArgs.type = FS_DIRECTORY;
  413.     Fs_SetIDs(procPtr, &openArgs.id);
  414.     openArgs.clientID = rpc_SpriteID;
  415.     if (procPtr->genFlags & PROC_FOREIGN) {
  416.     openArgs.migClientID    = procPtr->peerHostID;
  417.     } else {
  418.     openArgs.migClientID    = rpc_SpriteID;
  419.     }
  420.     fs_Stats.cltName.makeDirs++;
  421.     status = Fsprefix_LookupOperation(name, FS_DOMAIN_MAKE_DIR, FS_FOLLOW,
  422.             (Address)&openArgs, (Address)NIL, (Fs_NameInfo *)NIL);
  423.     return(status);
  424. }
  425.  
  426. /*
  427.  *----------------------------------------------------------------------
  428.  *
  429.  * Fs_ChangeDir --
  430.  *
  431.  *    Change the process's current directory.  This opens the
  432.  *    new current directory, and if that's successful the
  433.  *    old one is closed.
  434.  *
  435.  * Results:
  436.  *    An error code.
  437.  *
  438.  * Side effects:
  439.  *    Change the current directory.
  440.  *
  441.  *----------------------------------------------------------------------
  442.  */
  443. ReturnStatus
  444. Fs_ChangeDir(pathName)
  445.     char *pathName;
  446. {
  447.     register    Fs_ProcessState *fsPtr;
  448.     Fs_Stream        *newCwdPtr;    /* A stream is used because it has
  449.                      * a reference count and can be
  450.                      * closed with existing routines. */
  451.     ReturnStatus    status;
  452.  
  453.     fsPtr = (Proc_GetEffectiveProc())->fsPtr;
  454.  
  455.     /*
  456.      * FS_EXECUTE permission needed to change to a directory.
  457.      */
  458.     newCwdPtr = (Fs_Stream *)NIL;
  459.     fs_Stats.cltName.chdirs++;
  460.     status = Fs_Open(pathName, FS_EXECUTE | FS_FOLLOW, FS_DIRECTORY, 0,
  461.                   &newCwdPtr);
  462.     if (status) {
  463.     return(status);
  464.     }
  465.     (void)Fs_Close(fsPtr->cwdPtr);
  466.     fsPtr->cwdPtr = newCwdPtr;
  467.     return(SUCCESS);
  468. }
  469.  
  470. /*
  471.  *----------------------------------------------------------------------
  472.  *
  473.  * Fs_Trunc --
  474.  *
  475.  *    Truncate a file to a given length given its pathname.
  476.  *
  477.  * Results:
  478.  *    An error code
  479.  *
  480.  * Side effects:
  481.  *    The files length gets set and any data beyond that is deleted.
  482.  *
  483.  *----------------------------------------------------------------------
  484.  */
  485. ReturnStatus
  486. Fs_Trunc(pathName, length)
  487.     char *pathName;
  488.     int length;
  489. {
  490.     Fs_Stream *streamPtr;
  491.     ReturnStatus status;
  492.  
  493.     streamPtr = (Fs_Stream *)NIL;
  494.     status = Fs_Open(pathName, FS_WRITE | FS_FOLLOW, FS_FILE, 0, &streamPtr);
  495.     if (status != SUCCESS) {
  496.     return(status);
  497.     }
  498.     status = Fs_TruncStream(streamPtr, length);
  499.     (void)Fs_Close(streamPtr);
  500.     return(status);
  501. }
  502.  
  503. /*
  504.  *----------------------------------------------------------------------
  505.  *
  506.  * Fs_TruncStream --
  507.  *
  508.  *    Truncate a file to a given length given an open stream.
  509.  *    This is a thin layer on top of Fs_IOControl that is called
  510.  *    from Fs_Trunc and from Fs_Open.
  511.  *
  512.  * Results:
  513.  *    An error code
  514.  *
  515.  * Side effects:
  516.  *    The files length gets set and any data beyond that is deleted.
  517.  *
  518.  *----------------------------------------------------------------------
  519.  */
  520. ReturnStatus
  521. Fs_TruncStream(streamPtr, length)
  522.     Fs_Stream *streamPtr;
  523.     int length;
  524. {
  525.     ReturnStatus status;
  526.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  527.     Fs_IOCParam ioctl;
  528.     Fs_IOReply reply;
  529.  
  530.     if (length < 0) {
  531.     return(GEN_INVALID_ARG);
  532.     }
  533.     ioctl.command = IOC_TRUNCATE;
  534.     ioctl.inBuffer = (Address)&length;
  535.     ioctl.inBufSize = sizeof(int);
  536.     ioctl.outBuffer = (Address) NIL;
  537.     ioctl.outBufSize = 0;
  538.     ioctl.format = fsMach_Format;
  539.     ioctl.procID = procPtr->processID;
  540.     ioctl.familyID = procPtr->familyID;
  541.     ioctl.uid = procPtr->effectiveUserID;
  542.     ioctl.flags = 0;
  543.  
  544.     status = Fs_IOControl(streamPtr, &ioctl, &reply);
  545.     return(status);
  546. }
  547.  
  548. /*
  549.  *----------------------------------------------------------------------
  550.  *
  551.  * Fs_GetAttributes --
  552.  *
  553.  *    Get the attributes of a file given its name.  First the name server
  554.  *    is contacted to get the initial version of the attributes.  Then
  555.  *    the I/O server is contacted to update attributes like the
  556.  *    access and modify times.
  557.  *
  558.  * Results:
  559.  *    An error code and the attributes.
  560.  *
  561.  * Side effects:
  562.  *    None here.
  563.  *
  564.  *----------------------------------------------------------------------
  565.  */
  566.  
  567. ReturnStatus
  568. Fs_GetAttributes(pathName, fileOrLink, attrPtr)
  569.     char *pathName;
  570.     int fileOrLink;        /* FS_ATTRIB_FILE or FS_ATTRIB_LINK */
  571.     Fs_Attributes *attrPtr;
  572. {
  573.     ReturnStatus status;
  574.     Fs_OpenArgs openArgs;
  575.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  576.     Fs_GetAttrResults getAttrResults;    /* References attrPtr and ioFileID */
  577.     Fs_FileID ioFileID;            /* Returned from name server, indicates
  578.                      * who the I/O server is. */
  579.  
  580.     openArgs.useFlags = (fileOrLink == FS_ATTRIB_LINK) ? 0 : FS_FOLLOW;
  581.     openArgs.permissions = 0;
  582.     openArgs.type = FS_FILE;
  583.     openArgs.clientID = rpc_SpriteID;
  584.     Fs_SetIDs(procPtr, &openArgs.id);
  585.     if (procPtr->genFlags & PROC_FOREIGN) {
  586.     openArgs.migClientID    = procPtr->peerHostID;
  587.     } else {
  588.     openArgs.migClientID    = rpc_SpriteID;
  589.     }
  590.  
  591.     getAttrResults.attrPtr = attrPtr;
  592.     getAttrResults.fileIDPtr = &ioFileID;
  593.  
  594.     /*
  595.      * Get an initial version of the attributes from the name server.
  596.      */
  597.     fs_Stats.cltName.getAttrs++;
  598.     status = Fsprefix_LookupOperation(pathName, FS_DOMAIN_GET_ATTR, openArgs.useFlags,
  599.          (Address)&openArgs, (Address)&getAttrResults,
  600.          (Fs_NameInfo *)NIL);
  601.     if ((status == SUCCESS) &&
  602.     (ioFileID.type > 0 && ioFileID.type <= FSIO_NUM_STREAM_TYPES)) {
  603.     /*
  604.      * Update those with attributes cached at the I/O server.
  605.      * This is suppressed by setting the ioFileID.type < 0
  606.      */
  607.     fs_Stats.cltName.getIOAttrs++;
  608.     status = (*fsio_StreamOpTable[ioFileID.type].getIOAttr)
  609.             (&ioFileID, rpc_SpriteID, attrPtr);
  610. #ifdef lint
  611.     status = Fsrmt_GetIOAttr(&ioFileID, rpc_SpriteID, attrPtr);
  612.     status = FsrmtFileGetIOAttr(&ioFileID, rpc_SpriteID, attrPtr);
  613.     status = Fsio_DeviceGetIOAttr(&ioFileID, rpc_SpriteID, attrPtr);
  614.     status = Fsio_PipeGetIOAttr(&ioFileID, rpc_SpriteID, attrPtr);
  615. #endif lint
  616.     }
  617.     return(status);
  618. }
  619.  
  620. /*
  621.  *----------------------------------------------------------------------
  622.  *
  623.  * Fs_SetAttributes --
  624.  *
  625.  *    Set some attributes of a file given its name.  The input contains
  626.  *    the complete set of attributes for the file but not all of these
  627.  *    are affected by this call.  Ie.  the user can't change everything.
  628.  *    The name server is contacted first to set attributes file descriptor,
  629.  *    then the I/O server is contacted to update cached attributes.
  630.  *
  631.  * Results:
  632.  *    An error code
  633.  *
  634.  * Side effects:
  635.  *    See FsLocalSetAttrID for which attributes get updated at the
  636.  *    file server.
  637.  *
  638.  *     If the operation is successful, the count of setAttrs is incremented.
  639.  *
  640.  *----------------------------------------------------------------------
  641.  */
  642. ReturnStatus
  643. Fs_SetAttributes(pathName, fileOrLink, attrPtr, flags)
  644.     char *pathName;
  645.     int fileOrLink;
  646.     Fs_Attributes *attrPtr;
  647.     int flags;
  648. {
  649.     register ReturnStatus status;
  650.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  651.     Fs_SetAttrArgs setAttrArgs;        /* Bundled openArgs and attributes */
  652.     Fs_OpenArgs *openArgsPtr;        /* Pointer into setAttrArgs */
  653.     Fs_FileID ioFileID;            /* Used to get to I/O server */
  654.  
  655.     openArgsPtr = &setAttrArgs.openArgs;
  656.     openArgsPtr->useFlags = FS_OWNERSHIP;
  657.     if (fileOrLink == FS_ATTRIB_FILE) {
  658.     openArgsPtr->useFlags |= FS_FOLLOW;
  659.     }
  660.     openArgsPtr->permissions = 0;
  661.     openArgsPtr->type = FS_FILE;
  662.     openArgsPtr->clientID = rpc_SpriteID;
  663.     Fs_SetIDs(procPtr, &openArgsPtr->id);
  664.     if (procPtr->genFlags & PROC_FOREIGN) {
  665.     openArgsPtr->migClientID = procPtr->peerHostID;
  666.     } else {
  667.     openArgsPtr->migClientID = rpc_SpriteID;
  668.     }
  669.  
  670.     /*
  671.      * This copy is done here to avoid doing it in the client RPC stub.
  672.      */
  673.     setAttrArgs.attr = *attrPtr;
  674.     setAttrArgs.flags = flags;
  675.  
  676.     /*
  677.      * Set the attributes at the name server.  We get in return a fileID
  678.      * for the actual device which specifies a serverID.
  679.      */
  680.     fs_Stats.cltName.setAttrs++;
  681.     status = Fsprefix_LookupOperation(pathName, FS_DOMAIN_SET_ATTR, 0,
  682.              (Address)&setAttrArgs, (Address)&ioFileID,
  683.              (Fs_NameInfo *)NIL);
  684.     if ((status == SUCCESS) &&
  685.     (ioFileID.type > 0 && ioFileID.type <= FSIO_NUM_STREAM_TYPES)) {
  686.     /*
  687.      * Set the attributes at the I/O server.
  688.      */
  689.     fs_Stats.cltName.setIOAttrs++;
  690.     status = (*fsio_StreamOpTable[ioFileID.type].setIOAttr)
  691.             (&ioFileID, attrPtr, flags);
  692. #ifdef lint
  693.     status = Fsrmt_SetIOAttr(&ioFileID, attrPtr, flags);
  694.     status = FsrmtFileSetIOAttr(&ioFileID, attrPtr, flags);
  695.     status = Fsio_DeviceSetIOAttr(&ioFileID, attrPtr, flags);
  696.     status = Fsio_PipeSetIOAttr(&ioFileID, attrPtr, flags);
  697. #endif lint
  698.     }
  699.     return(status);
  700. }
  701.  
  702. /*
  703.  *----------------------------------------------------------------------
  704.  *
  705.  * Fs_HardLink --
  706.  *
  707.  *      Make two pathnames refer to the same file.  The pathnames are
  708.  *      restricted to be in the same domain, ie. stored on the same
  709.  *      disk pack, so the file server can make the link.
  710.  *
  711.  * Results:
  712.  *      SUCCESS if the link was made.  FS_CANT_LINK if the pathnames
  713.  *      are not in the same domain.
  714.  *
  715.  * Side effects:
  716.  *      Cause the two pathnames to refer to the same file.
  717.  *
  718.  *----------------------------------------------------------------------
  719.  */
  720. ReturnStatus
  721. Fs_HardLink(pathName, linkName)
  722.     char *pathName;    /* Name of the existing file */
  723.     char *linkName;    /* Name of the file to create which is a link to
  724.              * the existing file */
  725. {
  726.     ReturnStatus status;
  727.     Fs_LookupArgs lookupArgs;
  728.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  729.  
  730.     lookupArgs.useFlags = FS_LINK;
  731.     Fs_SetIDs(procPtr, &lookupArgs.id);
  732.     lookupArgs.clientID = rpc_SpriteID;
  733.     if (procPtr->genFlags & PROC_FOREIGN) {
  734.     lookupArgs.migClientID    = procPtr->peerHostID;
  735.     } else {
  736.     lookupArgs.migClientID    = rpc_SpriteID;
  737.     }
  738.     fs_Stats.cltName.hardLinks++;
  739.     status = Fsprefix_TwoNameOperation(FS_DOMAIN_HARD_LINK, pathName, linkName,
  740.                              &lookupArgs);
  741.     return(status);
  742. }
  743.  
  744. /*
  745.  *----------------------------------------------------------------------
  746.  *
  747.  * Fs_Rename --
  748.  *
  749.  *    Change the name of a file.  This is complicated because the files
  750.  *    can only be in the same domain.  This is not directly evident.
  751.  *
  752.  * Results:
  753.  *      SUCCESS if the name was changed.
  754.  *
  755.  * Side effects:
  756.  *    Change the name of a file.
  757.  *
  758.  *----------------------------------------------------------------------
  759.  */
  760. ReturnStatus
  761. Fs_Rename(pathName, newName)
  762.     char *pathName;    /* Name of the existing file */
  763.     char *newName;    /* The new pathname for the file */
  764. {
  765.     ReturnStatus status;
  766.     Fs_LookupArgs lookupArgs;
  767.     Proc_ControlBlock *procPtr = Proc_GetEffectiveProc();
  768.  
  769.     lookupArgs.useFlags = FS_LINK | FS_RENAME;
  770.     Fs_SetIDs(procPtr, &lookupArgs.id);
  771.     lookupArgs.clientID = rpc_SpriteID;
  772.     if (procPtr->genFlags & PROC_FOREIGN) {
  773.     lookupArgs.migClientID    = procPtr->peerHostID;
  774.     } else {
  775.     lookupArgs.migClientID    = rpc_SpriteID;
  776.     }
  777.     fs_Stats.cltName.renames++;
  778.     status = Fsprefix_TwoNameOperation(FS_DOMAIN_RENAME, pathName, newName,
  779.                           &lookupArgs);
  780.     return(status);
  781. }
  782.  
  783. /*
  784.  *----------------------------------------------------------------------
  785.  *
  786.  * Fs_SymLink --
  787.  *
  788.  *    Create a symbolic link file by writing the name of the target
  789.  *    file (including the NULL) into the link file.  This only
  790.  *    succeeds if the link file does not already exist.
  791.  *
  792.  * Results:
  793.  *      SUCCESS if the link was created.
  794.  *
  795.  * Side effects:
  796.  *    Create the file and write the link name into it.
  797.  *
  798.  *----------------------------------------------------------------------
  799.  */
  800. ReturnStatus
  801. Fs_SymLink(targetName, linkName, remoteFlag)
  802.     char *targetName;    /* Name of the file to link to */
  803.     char *linkName;    /* The name of the new link file that's created */
  804.     Boolean remoteFlag;    /* TRUE => link will be a REMOTE_LINK */
  805. {
  806.     ReturnStatus status;
  807.     Fs_Stream *streamPtr;
  808.     int length;
  809.  
  810.     if (remoteFlag) {
  811.     /*
  812.      * Could check for super-user only here.
  813.      */
  814.     if (targetName[0] != '/') {
  815.         /*
  816.          * Remote links must be absolute.  They should also be circular,
  817.          * but that is harder to check.
  818.          */
  819.         return(FS_INVALID_ARG);
  820.     }
  821.     }
  822.     fs_Stats.cltName.symLinks++;
  823.     status = Fs_Open(linkName, FS_CREATE | FS_WRITE | FS_EXCLUSIVE,
  824.                 (remoteFlag ? FS_REMOTE_LINK : FS_SYMBOLIC_LINK),
  825.                 0777, &streamPtr);
  826.     if (status == SUCCESS) {
  827.     length = strlen(targetName) + 1;    /* FIX */
  828.     status = Fs_Write(streamPtr, targetName, 0, &length);
  829.     (void)Fs_Close(streamPtr);
  830.     }
  831.     return(status);
  832. }
  833.